#include "HttpConnection.h"
#include "LogicSystem.h"
// 十六进制编码辅助函数
unsigned char ToHex(unsigned char x)
{
    return  x > 9 ? x + 55 : x + 48;
}
// 十六进制解码辅助函数
unsigned char FromHex(unsigned char x)
{
    unsigned char y;
    if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
    else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
    else if (x >= '0' && x <= '9') y = x - '0';
    else assert(0);
    return y;
}
// URL 编码函数
std::string UrlEncode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        //判断是否仅有数字和字母构成
        if (isalnum((unsigned char)str[i]) ||
            (str[i] == '-') ||
            (str[i] == '_') ||
            (str[i] == '.') ||
            (str[i] == '~'))
            strTemp += str[i];
        else if (str[i] == ' ') //为空字符
            strTemp += "+";
        else
        {
            //其他字符需要提前加%并且高四位和低四位分别转为16进制
            strTemp += '%';
            strTemp += ToHex((unsigned char)str[i] >> 4);
            strTemp += ToHex((unsigned char)str[i] & 0x0F);
        }
    }
    return strTemp;
}

// URL 解码函数
std::string UrlDecode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        //还原+为空
        if (str[i] == '+') strTemp += ' ';
        //遇到%将后面的两个字符从16进制转为char再拼接
        else if (str[i] == '%')
        {
            assert(i + 2 < length);
            unsigned char high = FromHex((unsigned char)str[++i]);
            unsigned char low = FromHex((unsigned char)str[++i]);
            strTemp += high * 16 + low;
        }
        else strTemp += str[i];
    }
    return strTemp;
}
// 构造函数，初始化 socket
HttpConnection::HttpConnection(boost::asio::io_context& ioc):_socket(ioc)
{
}

// 启动 HTTP 连接处理，开始异步读取客户端的 HTTP 请求
void HttpConnection::Start()
{
    auto self = shared_from_this();
    // 异步读取客户端发送的 HTTP 请求
    // _socket 是用于与客户端通信的套接字
    // _buffer 是用于存储读取数据的缓冲区
    // _request 是存储解析后的 HTTP 请求的对象
    // 传入的 lambda 函数是异步读取操作完成后的回调函数
    http::async_read(_socket, _buffer, _request, [self](beast::error_code ec,
        std::size_t bytes_transferred) {
            try
            {
                // 检查异步读取操作是否出现错误
                if (ec) {
                    // 如果出现错误，输出错误信息
                    std::cout << "http read err is " << ec.what() << std::endl;
                    // 直接返回，不再执行后续处理请求的代码
                    return;
                }

                // 忽略读取的字节数，因为在 HTTP 连接中不需要考虑粘包问题
                // HTTP 协议本身已经对消息进行了明确的分隔，所以不需要额外处理粘包
                boost::ignore_unused(bytes_transferred);

                // 调用 HandleReq 方法处理读取到的 HTTP 请求
                // 该方法会根据请求内容生成相应的响应
                self->HandleReq();

                // 启动定时器检查连接是否超时
                // 防止客户端长时间无响应占用服务器资源
                self->CheckDeadline();
            }
            catch (const std::exception& exp)
            {
                // 捕获在处理请求过程中可能抛出的异常
                // 输出异常信息，方便调试和监控
                std::cout << "exception is " << exp.what() << std::endl;
            }
        });
}

// 检查连接超时，如果超时则关闭 socket
void HttpConnection::CheckDeadline()
{
    auto self = shared_from_this();
    deadline_.async_wait(
        [self](beast::error_code ec)
        {
            if (!ec)
            {
                // Close socket to cancel any outstanding operation.
                self->_socket.close(ec);
            }
        });
}
// 发送 HTTP 响应给客户端
void HttpConnection::WriteResponse()
{
    auto self = shared_from_this();
    // 设置响应的 Content-Length 头部字段，其值为响应体的字节大小
    // 这样客户端可以根据该字段准确知道响应体的长度，避免数据接收不完整或接收过多数据的问题
    _response.content_length(_response.body().size());
    // 发起一个异步写操作，将 _response 中的 HTTP 响应数据通过 _socket 发送给客户端
    http::async_write(_socket, _response,
        [self](beast::error_code ec, std::size_t)
        {
            // 关闭套接字的发送端，通知客户端服务器不再发送数据
            // 第一个参数指定要关闭的方向为发送端，第二个参数 ec 用于接收关闭操作可能产生的错误码
            self->_socket.shutdown(tcp::socket::shutdown_send, ec);

            // 取消之前启动的定时器
            // 定时器通常用于设置操作的超时时间，这里写操作完成了，所以取消定时器以避免不必要的超时处理
            self->deadline_.cancel();
        });
}
// 处理 HTTP 请求，根据 GET/POST 分发业务逻辑
void HttpConnection::HandleReq()
{
    _response.version(_request.version());
    _response.keep_alive(false);
    if (_request.method() == http::verb::get) {
        PreParseGetParam();
        bool success = LogicSystem::GetInstance()->HandleGet(_get_url, shared_from_this());
        if (!success) {
            _response.result(http::status::not_found);
            _response.set(http::field::content_type, "text/plain");
            beast::ostream(_response.body()) << "url not found\r\n";
            WriteResponse();
            return;
        }
        _response.result(http::status::ok);
        _response.set(http::field::server, "GateServer");
        WriteResponse();
        return;
    }
    if (_request.method() == http::verb::post) {
        bool success = LogicSystem::GetInstance()->HandlePost(_request.target(), shared_from_this());
        if (!success) {
            _response.result(http::status::not_found);
            _response.set(http::field::content_type, "text/plain");
            beast::ostream(_response.body()) << "url not found\r\n";
            WriteResponse();
            return;
        }
        _response.result(http::status::ok);
        _response.set(http::field::server, "GateServer");
        WriteResponse();
        return;
    }
}

// 解析 GET 请求参数
void HttpConnection::PreParseGetParam()
{
    // 提取 URI  
    auto uri = _request.target();

    // 查找查询字符串的开始位置（即 '?' 的位置）  
    auto query_pos = uri.find('?');
    if (query_pos == std::string::npos) {
        _get_url = uri;
        return;
    }

    _get_url = uri.substr(0, query_pos);
    std::string query_string = uri.substr(query_pos + 1);
    std::string key;
    std::string value;
    size_t pos = 0;
    while ((pos = query_string.find('&')) != std::string::npos)
    {
        auto pair = query_string.substr(0, pos);
        auto eq_pos = pair.find('=');
        if (eq_pos != std::string::npos) {
            key = UrlDecode(pair.substr(0, eq_pos));
            value = UrlDecode(pair.substr(eq_pos + 1));
            _get_params[key] = value;
        }
        query_string.erase(0,pos + 1);
    }
    // 处理最后一个参数对（如果没有 & 分隔符） 
    if (!query_string.empty()) {
        auto eq_pos = query_string.find('=');
        key = UrlDecode(query_string.substr(0, eq_pos));
        value = UrlDecode(query_string.substr(eq_pos + 1));
        _get_params[key] = value;
    }
}




